﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ISE;

using Tao.OpenGl;

using HongsLibrary.Core.Box2D.Dynamics;
using HongsLibrary.Common;


namespace HongsLibrary.Core.OpenGL
{
    using Box2DXMath = Common.Math;
    using SysMath = System.Math;
    using System.Windows.Forms;

    // This class implements debug drawing callbacks that are invoked
	// inside World.Step.
    public class OpenGLDebugDraw : DebugDraw
    {
        #region Members
        static FTFont _sysfont;
        static Tao.Platform.Windows.SimpleOpenGlControl _openGlControl;
        private static bool _sIsTextRendererInitialized = false;


        #endregion Members

        #region Override Method
        public override void DrawPolygon(Vector2[] vertices, int vertexCount, Color color)
        {
            Gl.glColor3f(color.R, color.G, color.B);
            Gl.glBegin(Gl.GL_LINE_LOOP);
            for (int i = 0; i < vertexCount; ++i)
            {
                Gl.glVertex2f(vertices[i].X, vertices[i].Y);
            }
            Gl.glEnd();
        }
        public override void DrawSolidPolygon(Vector2[] vertices, int vertexCount, Color color)
        {
            Gl.glEnable(Gl.GL_BLEND);
            Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
            Gl.glColor4f(0.5f * color.R, 0.5f * color.G, 0.5f * color.B, 0.5f);
            Gl.glBegin(Gl.GL_TRIANGLE_FAN);
            for (int i = 0; i < vertexCount; ++i)
            {
                Gl.glVertex2f(vertices[i].X, vertices[i].Y);
            }
            Gl.glEnd();
            Gl.glDisable(Gl.GL_BLEND);

            Gl.glColor4f(color.R, color.G, color.B, 1.0f);
            Gl.glBegin(Gl.GL_LINE_LOOP);
            for (int i = 0; i < vertexCount; ++i)
            {
                Gl.glVertex2f(vertices[i].X, vertices[i].Y);
            }
            Gl.glEnd();
        }
        public override void DrawCircle(Vector2 center, float radius, Color color)
        {
            float k_segments = 16.0f;
            float k_increment = 2.0f * Common.Settings.Pi / k_segments;
            float theta = 0.0f;
            Gl.glColor3f(color.R, color.G, color.B);
            Gl.glBegin(Gl.GL_LINE_LOOP);
            for (int i = 0; i < k_segments; ++i)
            {
                Vector2 v = center + radius * new Vector2((float)SysMath.Cos(theta), (float)SysMath.Sin(theta));
                Gl.glVertex2f(v.X, v.Y);
                theta += k_increment;
            }
            Gl.glEnd();
        }

        public override void DrawSolidCircle(Vector2 center, float radius, Vector2 axis, Color color)
        {
            float k_segments = 16.0f;
            float k_increment = 2.0f * Common.Settings.Pi / k_segments;
            float theta = 0.0f;
            Gl.glEnable(Gl.GL_BLEND);
            Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
            Gl.glColor4f(0.5f * color.R, 0.5f * color.G, 0.5f * color.B, 0.5f);
            Gl.glBegin(Gl.GL_TRIANGLE_FAN);
            for (int i = 0; i < k_segments; ++i)
            {
                Vector2 v = center + radius * new Vector2((float)SysMath.Cos(theta), (float)SysMath.Sin(theta));
                Gl.glVertex2f(v.X, v.Y);
                theta += k_increment;
            }
            Gl.glEnd();
            Gl.glDisable(Gl.GL_BLEND);

            theta = 0.0f;
            Gl.glColor4f(color.R, color.G, color.B, 1.0f);
            Gl.glBegin(Gl.GL_LINE_LOOP);
            for (int i = 0; i < k_segments; ++i)
            {
                Vector2 v = center + radius * new Vector2((float)SysMath.Cos(theta), (float)SysMath.Sin(theta));
                Gl.glVertex2f(v.X, v.Y);
                theta += k_increment;
            }
            Gl.glEnd();

            Vector2 p = center + radius * axis;
            Gl.glBegin(Gl.GL_LINES);
            Gl.glVertex2f(center.X, center.Y);
            Gl.glVertex2f(p.X, p.Y);
            Gl.glEnd();
        }

        public override void DrawSegment(Vector2 p1, Vector2 p2, Color color)
        {
            Gl.glColor3f(color.R, color.G, color.B);
            Gl.glBegin(Gl.GL_LINES);
            Gl.glVertex2f(p1.X, p1.Y);
            Gl.glVertex2f(p2.X, p2.Y);
            Gl.glEnd();
        }

        public override void DrawXForm(XForm xf)
        {
            Vector2 p1 = xf.Position, p2;
            float k_axisScale = 0.4f;
            Gl.glBegin(Gl.GL_LINES);

            Gl.glColor3f(1.0f, 0.0f, 0.0f);
            Gl.glVertex2f(p1.X, p1.Y);
            p2 = p1 + k_axisScale * xf.R.Col1;
            Gl.glVertex2f(p2.X, p2.Y);

            Gl.glColor3f(0.0f, 1.0f, 0.0f);
            Gl.glVertex2f(p1.X, p1.Y);
            p2 = p1 + k_axisScale * xf.R.Col2;
            Gl.glVertex2f(p2.X, p2.Y);

            Gl.glEnd();
        }

        public static void DrawPoint(Vector2 p, float size, Color color)
        {
            Gl.glPointSize(size);
            Gl.glBegin(Gl.GL_POINTS);
            Gl.glColor3f(color.R, color.G, color.B);
            Gl.glVertex2f(p.X, p.Y);
            Gl.glEnd();
            Gl.glPointSize(1.0f);
        }

        public static void DrawSegment(Vector2 p1, Vector2 p2, Color color, params object[] p)
        {
            Gl.glColor3f(color.R, color.G, color.B);
            Gl.glBegin(Gl.GL_LINES);
            Gl.glVertex2f(p1.X, p1.Y);
            Gl.glVertex2f(p2.X, p2.Y);
            Gl.glEnd();
        }

        #endregion Override Method

        public static void DrawString(int x, int y, string str)
        {
            if (_sIsTextRendererInitialized)
            {
                Gl.glMatrixMode(Gl.GL_PROJECTION);
                Gl.glPushMatrix();
                Gl.glLoadIdentity();

                Gl.glMatrixMode(Gl.GL_MODELVIEW);
                Gl.glPushMatrix();
                Gl.glLoadIdentity();

                float xOffset = -0.95f + (float)x / ((float)_openGlControl.Width / 2f);
                float yOffset = 0.95f - (float)y / ((float)_openGlControl.Height / 2f);
                // Offset the font on the screen
                Gl.glTranslatef(xOffset, yOffset, 0);

                Gl.glColor3f(0.9f, 0.6f, 0.6f);
                // Scale the font
                Gl.glScalef(0.0035f, 0.0035f, 0.0035f);

                // Begin writing the font
                _sysfont.ftBeginFont();
                _sysfont.ftWrite(str);
                // Stop writing the font and restore old OpenGL parameters
                _sysfont.ftEndFont();

                Gl.glPopMatrix();
                Gl.glMatrixMode(Gl.GL_PROJECTION);
                Gl.glPopMatrix();
                Gl.glMatrixMode(Gl.GL_MODELVIEW);
            }
        }


        public static void InitTextRenderer(Tao.Platform.Windows.SimpleOpenGlControl openGlCtrl)
        {
            _openGlControl = openGlCtrl;

            try
            {
                int Errors = 0;
                // CREATE FONT
                _sysfont = new FTFont("FreeSans.ttf", out Errors);
                // INITIALISE FONT AS A PER_CHARACTER TEXTURE MAPPED FONT
                _sysfont.ftRenderToTexture(12, 196);
                // SET the sample font to align CENTERED
                _sysfont.FT_ALIGN = FTFontAlign.FT_ALIGN_LEFT;
                _sIsTextRendererInitialized = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                _sIsTextRendererInitialized = false;
            }
        }


    }
}
